package rcs34.android.photopublishare;

import java.io.IOException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

public class ActivityLocation extends MapActivity implements LocationListener {
  private final String LOGTAG = getClass().getName();
  private PersistentData m;
  public Overlays overlays;
  private MapView mapView;
  private TextView textSelected;
  private Button buttonOk;
  private Geocoder geocoder;
  private final long locationMinTime = 3000;
  private final long locationMinDistance = 10;
  private final int e6 = 1000000;;
  private LocationManager locationManager;
  private MapController mapController;
  private Object locationMonitor = new Object();

  /**
   * Cool - holds everything what we want to remember during reconfiguration
   * 
   * @author Kocian
   * 
   */
  private class PersistentData {
    public Location locationGPS = null;
    public Location locationNet = null;
    public Drawable gpsMarker;
    public Drawable netMarker;
    public Drawable usrMarker;

    public OverlayItem usrOverlay;
    public OverlayItem gpsOverlay;
    public OverlayItem netOverlay;
    public OverlayItem selected; // Will point to one of the three above
    public boolean firstLocation = true;
    public boolean userSelect = false;

    public PersistentData() {
      gpsMarker = getResources().getDrawable(R.drawable.marker_gps);
      gpsMarker.setBounds(0, -gpsMarker.getIntrinsicHeight(),
          gpsMarker.getIntrinsicWidth(), 0);
      netMarker = getResources().getDrawable(R.drawable.marker_net);
      netMarker.setBounds(0, -netMarker.getIntrinsicHeight(),
          netMarker.getIntrinsicWidth(), 0);
      usrMarker = getResources().getDrawable(R.drawable.marker_usr);
      usrMarker.setBounds(0, -usrMarker.getIntrinsicHeight(),
          usrMarker.getIntrinsicWidth(), 0);
      gpsOverlay = new OverlayItem(new GeoPoint(0, 0), "GPS:", "Resolving...");
      gpsOverlay.setMarker(gpsMarker);
      netOverlay = new OverlayItem(new GeoPoint(0, 0), "NET:", "Resolving...");
      netOverlay.setMarker(netMarker);
      usrOverlay = new OverlayItem(new GeoPoint(0, 0), "User:", "Resolving...");
      usrOverlay.setMarker(usrMarker);
    }
  }

  @Override
  public Object onRetainNonConfigurationInstance() {
    return m;
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_location);
    mapView = (MapView) findViewById(R.id.location_mapView);
    m = (PersistentData) getLastNonConfigurationInstance();
    if (m == null) {
      m = new PersistentData();
    }
    overlays = new Overlays(m.usrMarker);
    m.usrOverlay=overlays.placeOverlay(m.usrOverlay, null, null, null);
    mapView.getOverlays().clear();
    mapView.getOverlays().add(overlays);
    mapView.postInvalidate();
    textSelected = (TextView) findViewById(R.id.locationTextSelected);
    buttonOk = (Button) findViewById(R.id.locationButtonOk);
    mapView.setBuiltInZoomControls(false);
    mapController = mapView.getController();
    geocoder = new Geocoder(this);
    locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    onLocationChanged(m.locationGPS);
    onLocationChanged(m.locationNet);
  }

  @Override
  protected void onResume() {
    super.onResume();
    providersChanged();
  }

  @Override
  protected void onPause() {
    super.onPause();
    locationManager.removeUpdates(this);
  }

  synchronized public void onLocationChanged(Location _location) {
    boolean animate = false;
    OverlayItem overlay = null;
    if (_location != null) {
      GeoPoint point = new GeoPoint((int) (_location.getLatitude() * e6),
          (int) (_location.getLongitude() * e6));
      if (_location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
        m.locationGPS = _location;
        m.gpsOverlay = overlays.placeOverlay(m.gpsOverlay, point, null, null);
        overlay = m.gpsOverlay;
        animate = !m.userSelect;
      } else if (_location.getProvider().equals(
          LocationManager.NETWORK_PROVIDER)) {
        m.locationNet = _location;
        m.netOverlay = overlays.placeOverlay(m.netOverlay, point, null, null);
        overlay = m.netOverlay;
        animate = (m.locationGPS == null) && !m.userSelect;
      }
      if (animate) {
        mapController.animateTo(point);
      }
      if (m.firstLocation) {
        m.firstLocation = false;
        mapController.zoomToSpan(10000, 10000);
      }
      AddressResolver addrResolver = new AddressResolver();
      addrResolver.execute(overlay);
    }
  }

  public void onProviderDisabled(String provider) {
    providersChanged();
  }

  public void onProviderEnabled(String provider) {
    providersChanged();
  }

  public void onStatusChanged(String provider, int status, Bundle extras) {
    providersChanged();
  }

  public void handleSetSources(View _view) {
    Intent settingIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
    startActivity(settingIntent);
  }

  public void handleSatellite(View _view) {
    mapView.setSatellite(!mapView.isSatellite());
  }

  public void handleHome(View _view) {
    Location location = null;
    if (m.locationGPS != null) {
      location = m.locationGPS;
    } else if (m.locationNet != null) {
      location = m.locationNet;
    }
    if (location != null) {
      GeoPoint point = new GeoPoint((int) (location.getLatitude() * e6),
          (int) (location.getLongitude() * e6));
      mapController.animateTo(point);
    }
  }

  public void handleOk(View _view) {
    Intent result = new Intent();
    Location location;
    if (m.selected == m.gpsOverlay) {
      location = m.locationGPS;
    } else if (m.selected == m.netOverlay) {
      location = m.locationNet;
    } else {
      location = new Location(LocationManager.PASSIVE_PROVIDER);
      location.setLatitude(m.selected.getPoint().getLatitudeE6() / (double) e6);
      location.setLongitude(m.selected.getPoint().getLongitudeE6()
          / (double) e6);
    }
    result.putExtra(GApp.EXTRA_GEOPOINT, location);
    setResult(Activity.RESULT_OK, result);
    finish();
  }

  public void handleZoomIn(View _view) {
    mapController.zoomIn();
  }

  public void handleZoomOut(View _view) {
    mapController.zoomOut();
  }

  private void providersChanged() {
    locationManager.removeUpdates(this);
    boolean enabledNetwork = locationManager
        .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    boolean enabledGPS = locationManager
        .isProviderEnabled(LocationManager.GPS_PROVIDER);
    if (enabledNetwork) {
      locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
          locationMinTime, locationMinDistance, this);
    }
    if (enabledGPS) {
      locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
          locationMinTime, locationMinDistance, this);
    }
  }

  private void setInfoToItem(OverlayItem _item, String _snippet) {
    if (_item == m.gpsOverlay) {
      m.gpsOverlay = overlays.placeOverlay(_item, null, null, _snippet);
    } else if (_item == m.netOverlay) {
      m.netOverlay = overlays.placeOverlay(_item, null, null, _snippet);
    } else if (_item == m.usrOverlay) {
      m.usrOverlay = overlays.placeOverlay(_item, null, null, _snippet);
    }
    if (m.selected != null) {
      textSelected.setText(m.selected.getTitle() + " "
          + m.selected.getSnippet());
    }
  }

  @Override
  protected boolean isRouteDisplayed() {
    return false;
  }

  private class AddressResolver extends
      AsyncTask<OverlayItem, Object, OverlayItem> {
    @Override
    protected OverlayItem doInBackground(OverlayItem... _overlayItem) {
      synchronized (locationMonitor) {
        String locInfo = "";
        List<Address> addrs = null;
        double lat = _overlayItem[0].getPoint().getLatitudeE6() / (double) 1E6;
        double lon = _overlayItem[0].getPoint().getLongitudeE6() / (double) 1E6;
        try {
          addrs = geocoder.getFromLocation(lat, lon, 1);
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        if (addrs != null && addrs.size() > 0) {
          locInfo += addrs.get(0).getAddressLine(0);
        } else {
          locInfo += lat + "/" + lon;
        }
        publishProgress(_overlayItem[0], locInfo);
        return _overlayItem[0];
      }
    }

    @Override
    protected void onProgressUpdate(Object... itemInfo) {
      setInfoToItem((OverlayItem) itemInfo[0], (String) itemInfo[1]);
    }
  }

  // Overlay
  private class Overlays extends ItemizedOverlay {
    private ArrayList<OverlayItem> overlays = new ArrayList<OverlayItem>();

    private GestureDetector gestureDetector;

    // Listen to just a long press
    private class MapGestureListener extends SimpleOnGestureListener {
      @Override
      public void onLongPress(MotionEvent _motion) {
        selection(_motion);
      }

      @Override
      public boolean onDoubleTap(MotionEvent _motion) {
        selection(_motion);
        return true;
      }

      private void selection(MotionEvent _motion) {
        Projection proj = mapView.getProjection();
        GeoPoint loc = proj.fromPixels((int) _motion.getX(),
            (int) _motion.getY());
        m.usrOverlay = placeOverlay(m.usrOverlay, loc, null, null);
        mapController.animateTo(loc);
        m.userSelect = true;
        AddressResolver addrResolver = new AddressResolver();
        addrResolver.execute(m.usrOverlay);
      }
    }

    public Overlays(Drawable defaultMarker) {
      super(defaultMarker);
      gestureDetector = new GestureDetector(GApp.context,
          new MapGestureListener());
    }

    public OverlayItem placeOverlay(OverlayItem _item, GeoPoint _point,
        String _title, String _snippet) {
      OverlayItem result = null;
      if (_item != null) {
        overlays.remove(_item);
        Drawable marker = _item.getMarker(0);
        GeoPoint point = _point;
        String title = _title;
        String snippet = _snippet;
        if (point == null) {
          point = _item.getPoint();
        }
        if (title == null) {
          title = _item.getTitle();
        }
        if (snippet == null) {
          snippet = _item.getSnippet();
        }
        result = new OverlayItem(point, title, snippet);
        result.setMarker(marker);
        overlays.add(result);
        populate();
        mapView.postInvalidate();
      }
      return result;
    }

    @Override
    protected OverlayItem createItem(int _index) {
      return overlays.get(_index);
    }

    @Override
    public int size() {
      return overlays.size();
    }

    @Override
    public boolean onTap(int _index) {
      m.selected = overlays.get(_index);
      textSelected.setText(m.selected.getTitle() + " "
          + m.selected.getSnippet());
      buttonOk.setEnabled(true);
      return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent _motion, MapView _mapView) {
      return gestureDetector.onTouchEvent(_motion);
    }
  }

}
